#include "TileForwardDisplacementMappingFX.h"

TileForwardDisplacementMappingFX::TileForwardDisplacementMappingFX(ID3D11Device* device)
	:AbstractFX(device, L"FX/TileForwardDisplacementMapping.fxo")
{
	//Create Input Layout
	InitInputLayout(device);
	//Init shader variables
	InitShaderVariablePointers();
}

TileForwardDisplacementMappingFX::~TileForwardDisplacementMappingFX()
{}
	
void TileForwardDisplacementMappingFX::InitInputLayout(ID3D11Device* device)
{
	//Fillout input layout description.
	const D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[] = 
	{
		{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,	 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0}
	};

	//Create our input layout 	
	CreateInputLayout(device, inputLayoutDesc, 4);
}

void TileForwardDisplacementMappingFX::InitShaderVariablePointers()
{
	dLightVar = effect->GetVariableByName("dirLightArray");
	dLightCountVar = effect->GetVariableByName("dLightCount")->AsScalar();
	eyePosWVar = effect->GetVariableByName("eyePositionW")->AsVector();

	worldVar = effect->GetVariableByName("world")->AsMatrix();
	viewProjVar = effect->GetVariableByName("viewProj")->AsMatrix();
	worldInvTransVar = effect->GetVariableByName("worldInvTranspose")->AsMatrix();
	worldViewProjVar = effect->GetVariableByName("worldViewProj")->AsMatrix();
	textureTransformVar = effect->GetVariableByName("textureTransform")->AsMatrix();
	materialVar = effect->GetVariableByName("mat");

	dispMapVar = effect->GetVariableByName("displacementMap")->AsShaderResource();
	textureMapVar = effect->GetVariableByName("textureMap")->AsShaderResource();
	hmVar = effect->GetVariableByName("heightMap")->AsShaderResource();

	heightScaleVar	   = effect->GetVariableByName("heightScale")->AsScalar();
	maxTessDistanceVar = effect->GetVariableByName("maxTessDistance")->AsScalar();
	minTessDistanceVar = effect->GetVariableByName("minTessDistance")->AsScalar();
	maxTessFactorVar   = effect->GetVariableByName("maxTessFactor")->AsScalar();
	minTessFactorVar   = effect->GetVariableByName("minTessFactor")->AsScalar();

	//Tile forward data
	llbVar   = effect->GetVariableByName("LightListBuffer")->AsShaderResource();
	llibVar  = effect->GetVariableByName("LightListIndexBuffer")->AsShaderResource();
	llsebVar = effect->GetVariableByName("LightListStartEndBuffer")->AsShaderResource();

	//Render target dimensions.
	rtWidthVar  = effect->GetVariableByName("rtWidth")->AsScalar();
	rtHeightVar = effect->GetVariableByName("rtHeight")->AsScalar();
	
	//Hemispherical lighting
	hemiColDownVar = effect->GetVariableByName("HemiColDown")->AsVector();
	hemiColRangeVar = effect->GetVariableByName("HemiColRange")->AsVector();
	
	//SSAO
	worldViewVar = effect->GetVariableByName("WorldView")->AsMatrix();
	viewVar = effect->GetVariableByName("View")->AsMatrix();
	ssaoMapVar = effect->GetVariableByName("SSAOMap")->AsShaderResource();
	ssaoWorldViewProjTexVar = effect->GetVariableByName("SSAOWorldViewProjTex")->AsMatrix();

	//Environment map
	envMapVar = effect->GetVariableByName("EnvironmentMap")->AsShaderResource();
	
	//Shadow map
	shadowMapVar = effect->GetVariableByName("ShadowMap")->AsShaderResource();
	shadowMapViewVar = effect->GetVariableByName("ShadowMapView")->AsMatrix();
	shadowMapProjVar = effect->GetVariableByName("ShadowMapProj")->AsMatrix();
	shadowMapToTexVar = effect->GetVariableByName("ShadowMapToTex")->AsMatrix();
}

void TileForwardDisplacementMappingFX::SetShaderResources(ID3D11ShaderResourceView* dispMap,
		ID3D11ShaderResourceView* tex, 
		ID3D11ShaderResourceView* hm)
{
	dispMapVar->SetResource(dispMap);
	textureMapVar->SetResource(tex);
	hmVar->SetResource(hm);
}

void TileForwardDisplacementMappingFX::SetPerFrameCbuffer(XMFLOAT3& eye, 
	DirectionalLight* dLights, unsigned dLightCount,
	ID3D11ShaderResourceView* lightListIndexBuffer, 
	ID3D11ShaderResourceView* lightListStartEndBuffer)
{
	//Cap D light count 
	if (dLightCount > MAX_DIRECTIONAL_LIGHT_COUNT)
		dLightCount = MAX_DIRECTIONAL_LIGHT_COUNT;
	eyePosWVar->SetRawValue(&eye, 0, sizeof(XMFLOAT3));
	dLightVar->SetRawValue(dLights, 0, sizeof(DirectionalLight) * dLightCount);
	dLightCountVar->SetInt(dLightCount);

	//Set llib and llseb
	llibVar->SetResource(lightListIndexBuffer);
	llsebVar->SetResource(lightListStartEndBuffer);
}

void TileForwardDisplacementMappingFX::SetPerObjectCbuffer(CXMMATRIX& world, CXMMATRIX& viewProj,
		CXMMATRIX& worldInvTrans, CXMMATRIX& worldViewProj,
		CXMMATRIX& texTrans, Material mat, 
		CXMMATRIX& worldView, CXMMATRIX &view)
{
	worldVar->SetMatrix(reinterpret_cast<const float*>(&world));
	viewProjVar->SetMatrix(reinterpret_cast<const float*>(&viewProj));
	worldInvTransVar->SetMatrix(reinterpret_cast<const float*>(&worldInvTrans));
	worldViewProjVar->SetMatrix(reinterpret_cast<const float*>(&worldViewProj));

	textureTransformVar->SetMatrix(reinterpret_cast<const float*>(&texTrans));

	materialVar->SetRawValue(&mat, 0, sizeof(Material));

	worldViewVar->SetMatrix(reinterpret_cast<const float*>(&worldView));
	viewVar->SetMatrix(reinterpret_cast<const float*>(&view));
}

void TileForwardDisplacementMappingFX::SetCbufferTessData(float heightScale,
	float maxTessDist, float minTessDist,
	float maxTessFact, float minTessFact)
{
	heightScaleVar->SetFloat(heightScale);
	maxTessDistanceVar->SetFloat(maxTessDist);
	minTessDistanceVar->SetFloat(minTessDist);
	maxTessFactorVar->SetFloat(maxTessFact);
	minTessFactorVar->SetFloat(minTessFact);
}

void TileForwardDisplacementMappingFX::SetRTDimensions(unsigned width, unsigned height)
{
	rtWidthVar->SetInt(width);
	rtHeightVar->SetInt(height);
}

void TileForwardDisplacementMappingFX::SetLightListBuffer(ID3D11ShaderResourceView* lightListBuffer)
{
	llbVar->SetResource(lightListBuffer);
}

void TileForwardDisplacementMappingFX::SetHemisphericalData(XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange)
{
	hemiColDownVar->SetRawValue(&hemiColDown, 0, sizeof(XMFLOAT3));
	hemiColRangeVar->SetRawValue(&hemiColRange, 0, sizeof(XMFLOAT3));
}

void TileForwardDisplacementMappingFX::SetSSAOData(ID3D11ShaderResourceView* ssaoTex, CXMMATRIX &transform)
{
	ssaoMapVar->SetResource(ssaoTex);
	ssaoWorldViewProjTexVar->SetMatrix(reinterpret_cast<const float*>(&transform));
}

void TileForwardDisplacementMappingFX::SetEnvironmentMap(ID3D11ShaderResourceView* envCubeMap)
{
	envMapVar->SetResource(envCubeMap);
}

void TileForwardDisplacementMappingFX::SetShadowMap(ID3D11ShaderResourceView* shadowMap)
{
	shadowMapVar->SetResource(shadowMap);
}

void TileForwardDisplacementMappingFX::SetShadowMapMatricies(CXMMATRIX &view, CXMMATRIX &proj, CXMMATRIX &toTex)
{
	shadowMapViewVar->SetMatrix(reinterpret_cast<const float*>(&view));
	shadowMapProjVar->SetMatrix(reinterpret_cast<const float*>(&proj));
	shadowMapToTexVar->SetMatrix(reinterpret_cast<const float*>(&toTex));
}